#include "stdafx.h"
#include "SoundStructure.h"

using	namespace MomogenkyouSystem;

//--------------------------------------------------------------------------------------
// Callback structure
//--------------------------------------------------------------------------------------

StreamingVoiceContext::StreamingVoiceContext()
:	BufferEndEvent(CreateEvent(NULL, false, false, NULL))
{
}

StreamingVoiceContext::~StreamingVoiceContext()
{
	CloseHandle(BufferEndEvent);
}

void	StreamingVoiceContext::OnVoiceProcessingPassStart(UINT32 BytesRequired)
{
	UNREFERENCED_PARAMETER(BytesRequired);
}

void	StreamingVoiceContext::OnVoiceProcessingPassEnd()	
{

}

void	StreamingVoiceContext::OnStreamEnd()
{

}

void	StreamingVoiceContext::OnBufferStart(void * pBufferContext)	
{	
	UNREFERENCED_PARAMETER(pBufferContext);	
}

void	StreamingVoiceContext::OnBufferEnd(void * pBufferContext)
{
	UNREFERENCED_PARAMETER(pBufferContext);
	SetEvent(BufferEndEvent);
}

void	StreamingVoiceContext::OnLoopEnd(void * pBufferContext)
{
	UNREFERENCED_PARAMETER(pBufferContext);
}

void	StreamingVoiceContext::OnVoiceError(void * pBufferContext, HRESULT Error)
{
	UNREFERENCED_PARAMETER(pBufferContext);
	UNREFERENCED_PARAMETER(Error);
}

//--------------------------------------------------------------------------------------
// Wavebank
//--------------------------------------------------------------------------------------

Wavebank::Wavebank() 
: m_pEntries(NULL)
{
}

Wavebank::~Wavebank()
{
	Release();
}

HRESULT Wavebank::Load(const std::string & Filename)
{
	Release();
	HANDLE	_hFile = CreateFileA(Filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0L, NULL);
	if(_hFile == INVALID_HANDLE_VALUE)
		return HRESULT_FROM_WIN32(GetLastError());
	// Read and verify m_Header
	DWORD bytes;
	if(!ReadFile(_hFile, &m_Header, sizeof(m_Header), &bytes, NULL)
		|| bytes != sizeof(m_Header))
	{
		CloseHandle(_hFile);
		return HRESULT_FROM_WIN32( GetLastError() );
	}

	if(m_Header.dwSignature != WAVEBANK_HEADER_SIGNATURE
		|| (WAVEBANK_HEADER_VERSION < m_Header.dwHeaderVersion))
	{
		CloseHandle(_hFile);
		return E_FAIL;
	}

	// Load wavebank data
	SetFilePointer(_hFile, m_Header.Segments[ WAVEBANK_SEGIDX_BANKDATA ].dwOffset, 0, SEEK_SET);

	if(!ReadFile(_hFile, &m_Data, sizeof(m_Data), &bytes, NULL) || bytes != sizeof(m_Data))
	{
		CloseHandle(_hFile);
		return HRESULT_FROM_WIN32( GetLastError() );
	}

	// Load entries
	DWORD cbEntries = m_Header.Segments[ WAVEBANK_SEGIDX_ENTRYMETADATA ].dwLength;

	if(m_Data.dwEntryCount != (cbEntries / sizeof( WAVEBANKENTRY ) ) )
	{
		CloseHandle(_hFile);
		return E_FAIL;
	}

	m_pEntries = new WAVEBANKENTRY[m_Data.dwEntryCount];

	SetFilePointer(_hFile, m_Header.Segments[ WAVEBANK_SEGIDX_ENTRYMETADATA ].dwOffset, 0, SEEK_SET);

	if( !ReadFile(_hFile, m_pEntries, cbEntries, &bytes, NULL)
		|| bytes != cbEntries )
	{
		if(m_pEntries != NULL)
		{	
			delete [] m_pEntries;
			m_pEntries = NULL;
		}
		CloseHandle(_hFile);
		return HRESULT_FROM_WIN32( GetLastError() );
	}

	CloseHandle( _hFile );
	return S_OK;
}

void    Wavebank::Release()
{
	if(m_pEntries != NULL)
	{	
		delete [] m_pEntries;
		m_pEntries = NULL;
	}
}

DWORD   Wavebank::GetEntryCount() const
{
	return m_Data.dwEntryCount;
}
DWORD   Wavebank::GetEntryLengthInBytes(DWORD index)
{
	return ( index < m_Data.dwEntryCount ) ? ( m_pEntries[index].PlayRegion.dwLength ) : 0;
}
DWORD   Wavebank::GetEntryOffset(DWORD index)
{
	return ( index < m_Data.dwEntryCount ) ? ( m_pEntries[index].PlayRegion.dwOffset ) : 0;
}

HRESULT Wavebank::GetEntryFormat(DWORD index, WAVEFORMATEX* pFormat)
{
	if( index >= m_Data.dwEntryCount || !m_pEntries )
		return E_FAIL;

	WAVEBANKMINIWAVEFORMAT & _MiniFormat = ( m_Data.dwFlags & WAVEBANK_FLAGS_COMPACT )
		? m_Data.CompactFormat : ( m_pEntries[index].Format );

	switch( _MiniFormat.wFormatTag )
	{
	case WAVEBANKMINIFORMAT_TAG_PCM:
		pFormat->wFormatTag = WAVE_FORMAT_PCM;
		pFormat->cbSize = 0;
		break;

	case WAVEBANKMINIFORMAT_TAG_ADPCM:
		pFormat->wFormatTag = WAVE_FORMAT_ADPCM;
		pFormat->cbSize = 32; /* MSADPCM_FORMAT_EXTRA_BYTES */
		{
			ADPCMWAVEFORMAT *	_padpcmFmt = reinterpret_cast<ADPCMWAVEFORMAT*>(pFormat);
			_padpcmFmt->wSamplesPerBlock = (WORD) _MiniFormat.AdpcmSamplesPerBlock();
			_MiniFormat.AdpcmFillCoefficientTable( _padpcmFmt );
		}
		break;

	case WAVEBANKMINIFORMAT_TAG_WMA:
		pFormat->wFormatTag = (_MiniFormat.wBitsPerSample & 0x1) ? WAVE_FORMAT_WMAUDIO3 : WAVE_FORMAT_WMAUDIO2;
		pFormat->cbSize = 0;
		break;

	default:
		// WAVEBANKMINIFORMAT_TAG_XMA is only valid for Xbox
		return E_FAIL;
	}

	pFormat->nChannels			= _MiniFormat.nChannels;
	pFormat->wBitsPerSample		= _MiniFormat.BitsPerSample();
	pFormat->nBlockAlign		= (WORD)_MiniFormat.BlockAlign();
	pFormat->nSamplesPerSec		= _MiniFormat.nSamplesPerSec;
	pFormat->nAvgBytesPerSec	= _MiniFormat.AvgBytesPerSec();

	return S_OK;
}